/**
 * @file redis_manager.cpp
 * @brief Redis缓存管理器的实现
 * @details 负责处理与Redis缓存服务器的所有交互，包括：
 *          - 缓存连接的建立和维护
 *          - 用户会话管理
 *          - 用户数据缓存
 *          - 错误处理和日志记录
 */

#include "redis_manager.hpp"
#include "../config/config.hpp"
#include "../utils/logger.hpp"
#include <nlohmann/json.hpp>

RedisManager& RedisManager::getInstance() {
    static RedisManager instance;
    return instance;
}

RedisManager::~RedisManager() {
    cleanup();
}

bool RedisManager::init() {
    try {
        // 从配置文件获取Redis连接参数
        auto& config = Config::getInstance();
        std::string host = config.getRedisHost();
        int port = config.getRedisPort();

        // 创建Redis连接
        context_ = redisConnect(host.c_str(), port);
        if (context_ == nullptr || context_->err) {
            if (context_) {
                Logger::getInstance().error("Redis connection error: {}", context_->errstr);
                redisFree(context_);
                context_ = nullptr;
            } else {
                Logger::getInstance().error("Redis connection error: cannot allocate redis context");
            }
            return false;
        }

        // 如果配置了密码，进行身份验证
        std::string password = config.getRedisPassword();
        if (!password.empty()) {
            redisReply* reply = (redisReply*)redisCommand(context_, "AUTH %s", password.c_str());
            if (reply == nullptr) {
                Logger::getInstance().error("Redis authentication error: no reply");
                cleanup();
                return false;
            }
            if (reply->type == REDIS_REPLY_ERROR) {
                Logger::getInstance().error("Redis authentication error: {}", reply->str);
                freeReplyObject(reply);
                cleanup();
                return false;
            }
            freeReplyObject(reply);
        }

        // 选择数据库
        int db = config.getRedisDb();
        redisReply* reply = (redisReply*)redisCommand(context_, "SELECT %d", db);
        if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
            Logger::getInstance().error("Redis SELECT error: {}", 
                reply ? reply->str : "no reply");
            if (reply) freeReplyObject(reply);
            cleanup();
            return false;
        }
        freeReplyObject(reply);

        connected_ = true;
        Logger::getInstance().info("Redis connection established successfully");
        return true;
    } catch (const std::exception& e) {
        Logger::getInstance().error("Redis initialization error: {}", e.what());
        return false;
    }
}

void RedisManager::cleanup() {
    if (context_) {
        redisFree(context_);
        context_ = nullptr;
        connected_ = false;
        Logger::getInstance().info("Redis connection closed");
    }
}

std::string RedisManager::makeKey(const std::string& prefix, const std::string& key) {
    return prefix + ":" + key;
}

bool RedisManager::setUserSession(const std::string& token, int userId, int expirySeconds) {
    if (!connected_) return false;

    std::string key = makeKey("session", token);
    redisReply* reply = (redisReply*)redisCommand(context_, "SETEX %s %d %d",
        key.c_str(), expirySeconds, userId);

    bool success = false;
    if (reply && reply->type != REDIS_REPLY_ERROR) {
        success = true;
    } else {
        Logger::getInstance().error("Failed to set user session in Redis");
    }

    if (reply) freeReplyObject(reply);
    return success;
}

int RedisManager::getUserSession(const std::string& token) {
    if (!connected_) return -1;

    std::string key = makeKey("session", token);
    redisReply* reply = (redisReply*)redisCommand(context_, "GET %s", key.c_str());

    int userId = -1;
    if (reply && reply->type == REDIS_REPLY_STRING) {
        userId = std::stoi(reply->str);
    }

    if (reply) freeReplyObject(reply);
    return userId;
}

bool RedisManager::removeUserSession(const std::string& token) {
    if (!connected_) return false;

    std::string key = makeKey("session", token);
    redisReply* reply = (redisReply*)redisCommand(context_, "DEL %s", key.c_str());

    bool success = false;
    if (reply && reply->type != REDIS_REPLY_ERROR) {
        success = true;
    }

    if (reply) freeReplyObject(reply);
    return success;
}

bool RedisManager::cacheUserData(const User& user) {
    if (!connected_) return false;

    nlohmann::json userData = {
        {"id", user.id},
        {"username", user.username},
        {"email", user.email},
        {"last_login", user.lastLogin}
    };

    std::string key = makeKey("user", std::to_string(user.id));
    redisReply* reply = (redisReply*)redisCommand(context_, "SETEX %s %d %s",
        key.c_str(), 3600, userData.dump().c_str());

    bool success = false;
    if (reply && reply->type != REDIS_REPLY_ERROR) {
        success = true;
    }

    if (reply) freeReplyObject(reply);
    return success;
}

std::shared_ptr<User> RedisManager::getCachedUser(int userId) {
    if (!connected_) return nullptr;

    std::string key = makeKey("user", std::to_string(userId));
    redisReply* reply = (redisReply*)redisCommand(context_, "GET %s", key.c_str());

    std::shared_ptr<User> user = nullptr;
    if (reply && reply->type == REDIS_REPLY_STRING) {
        try {
            auto userData = nlohmann::json::parse(reply->str);
            user = std::make_shared<User>();
            user->id = userData["id"];
            user->username = userData["username"];
            user->email = userData["email"];
            user->lastLogin = userData["last_login"];
        } catch (const std::exception& e) {
            Logger::getInstance().error("Failed to parse cached user data: {}", e.what());
        }
    }

    if (reply) freeReplyObject(reply);
    return user;
}

void RedisManager::removeCachedUser(int userId) {
    if (!connected_) return;

    std::string key = makeKey("user", std::to_string(userId));
    redisReply* reply = (redisReply*)redisCommand(context_, "DEL %s", key.c_str());

    if (reply) freeReplyObject(reply);
}

bool RedisManager::connect(const std::string& host, int port, const std::string& password) {
    // Implementation of connect method
    return false; // Placeholder return, actual implementation needed
}

void RedisManager::disconnect() {
    // Implementation of disconnect method
}

bool RedisManager::is_connected() const {
    // Implementation of is_connected method
    return false; // Placeholder return, actual implementation needed
}

bool RedisManager::set(const std::string& key, const std::string& value, int expirySeconds) {
    if (!connected_) return false;

    redisReply* reply;
    if (expirySeconds > 0) {
        reply = (redisReply*)redisCommand(context_, "SETEX %s %d %s",
            key.c_str(), expirySeconds, value.c_str());
    } else {
        reply = (redisReply*)redisCommand(context_, "SET %s %s",
            key.c_str(), value.c_str());
    }

    bool success = false;
    if (reply && reply->type != REDIS_REPLY_ERROR) {
        success = true;
    } else {
        Logger::getInstance().error("Failed to set key in Redis");
    }

    if (reply) freeReplyObject(reply);
    return success;
}

std::string RedisManager::get(const std::string& key) {
    if (!connected_) return "";

    redisReply* reply = (redisReply*)redisCommand(context_, "GET %s", key.c_str());
    std::string value;

    if (reply && reply->type == REDIS_REPLY_STRING) {
        value = reply->str;
    }

    if (reply) freeReplyObject(reply);
    return value;
}

bool RedisManager::del(const std::string& key) {
    if (!connected_) return false;

    redisReply* reply = (redisReply*)redisCommand(context_, "DEL %s", key.c_str());
    bool success = false;

    if (reply && reply->type != REDIS_REPLY_ERROR) {
        success = true;
    }

    if (reply) freeReplyObject(reply);
    return success;
}

bool RedisManager::exists(const std::string& key) {
    if (!connected_) return false;

    redisReply* reply = (redisReply*)redisCommand(context_, "EXISTS %s", key.c_str());
    bool exists = false;

    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        exists = reply->integer > 0;
    }

    if (reply) freeReplyObject(reply);
    return exists;
}

bool RedisManager::hset(const std::string& key, const std::string& field, 
              const std::string& value) {
    // Implementation of hset method
    return false; // Placeholder return, actual implementation needed
}

std::string RedisManager::hget(const std::string& key, const std::string& field) {
    // Implementation of hget method
    return ""; // Placeholder return, actual implementation needed
}

bool RedisManager::hdel(const std::string& key, const std::string& field) {
    // Implementation of hdel method
    return false; // Placeholder return, actual implementation needed
}

bool RedisManager::sadd(const std::string& key, const std::string& member) {
    // Implementation of sadd method
    return false; // Placeholder return, actual implementation needed
}

bool RedisManager::srem(const std::string& key, const std::string& member) {
    // Implementation of srem method
    return false; // Placeholder return, actual implementation needed
}

std::vector<std::string> RedisManager::smembers(const std::string& key) {
    // Implementation of smembers method
    return {}; // Placeholder return, actual implementation needed
}

bool RedisManager::expire(const std::string& key, const std::chrono::seconds& ttl) {
    // Implementation of expire method
    return false; // Placeholder return, actual implementation needed
}

std::chrono::seconds RedisManager::ttl(const std::string& key) {
    // Implementation of ttl method
    return std::chrono::seconds(0); // Placeholder return, actual implementation needed
}

// 初始化
RedisManager::getInstance().connect("localhost", 6379);
SessionStorage::get_instance().init();
SessionManager::get_instance().init();

// 创建会话
auto session = SessionManager::get_instance().create_session();
session->set_user_id(user_id);

// 存储其他数据
RedisManager::getInstance().set("game:room:123", "room_data"); 